feat: Add operation and type registry codegen#1033
feat: Add operation and type registry codegen#1033
Conversation
| ) { | ||
| writer.apply { | ||
| val paramsType = ctx.settings.sdkId.clientName() + "AuthSchemeResolverParameters" | ||
| val paramsType = ctx.settings.clientBaseNamePreservingService + "AuthSchemeResolverParameters" |
There was a problem hiding this comment.
Ensure the endpoint params name used currently is preserved after the previous sdkId refactor.
| httpBindingResolver: HttpBindingResolver, | ||
| defaultTimestampFormat: TimestampFormatTrait.Format, | ||
| ) { | ||
| if (SerdeUtils.useSchemaBased(ctx)) return |
There was a problem hiding this comment.
Don't generate any of the Codable, URLPathProvider, QueryStringProvider, etc. extensions if this is a schema-based service.
| class OperationInputBodyMiddleware( | ||
| val model: Model, | ||
| val symbolProvider: SymbolProvider, | ||
| val ctx: ProtocolGenerator.GenerationContext, |
There was a problem hiding this comment.
Simplified interface by taking ctx instead of separate model & symbol provider.
| ctx: ProtocolGenerator.GenerationContext, | ||
| writer: SwiftWriter, | ||
| inputSymbol: Symbol, | ||
| outputSymbol: Symbol, |
There was a problem hiding this comment.
The 4 files below were used to generate schemas using the Smithy-based code generator. Since those will be generated by the Swift-native code generator instead, they are deleted here.
| private fun usesSchemaBasedSerialization(ctx: ProtocolGenerator.GenerationContext): Boolean = | ||
| // This fun is temporary; it will be eliminated when all services/protocols are moved to schema-based | ||
| ctx.service.allTraits.keys | ||
| .any { it.name == "rpcv2Cbor" } |
There was a problem hiding this comment.
The function above was moved to SerdeUtils.
The functions below (generateSchemas() and various helpers) are no longer needed since schemas are generated in the native-Swift code generator.
There was a problem hiding this comment.
Previously used in the generation of schemas.
| LOGGER.info("[${service.id}] Generating Smithy model file info") | ||
| SmithyModelFileInfoGenerator(ctx).writeSmithyModelFileInfo() | ||
| LOGGER.info("[${service.id}] Generating swift-settings.json") | ||
| SwiftSettingsJSONGenerator(ctx).render() |
There was a problem hiding this comment.
Renamed smithy-model-info.json to swift-settings.json and aligned its contents with this code generator's SwiftSettings type.
| @@ -77,6 +59,24 @@ class SwiftSettings( | |||
| val modelPath: String, | |||
| ) { | |||
| companion object { | |||
There was a problem hiding this comment.
The strings below have been exposed so the swift-settings.json writer can access them.
|
|
||
| class SwiftSettingsJSONGenerator( | ||
| val ctx: ProtocolGenerator.GenerationContext, | ||
| ) { |
There was a problem hiding this comment.
Using Smithy's Node type to convert to JSON, this file writes the swift-settings.json file for the service.
|
|
||
| public static var unitSchema: Schema { | ||
| Schema(id: .init("smithy.api", "Unit"), type: .structure) | ||
| Schema(id: .init("smithy.api", "Unit"), type: .structure, traits: [UnitTypeTrait()]) |
There was a problem hiding this comment.
Add the UnitTypeTrait to the smithy.api#Unit schema.
| SensitiveTrait.id, | ||
| SparseTrait.id, | ||
| TimestampFormatTrait.id, | ||
| UnitTypeTrait.id, // UnitTypeTrait will only ever appear in Prelude.unitSchema |
There was a problem hiding this comment.
Above, new trait types are added to the runtime "allow list".
| import ArgumentParser | ||
| import Foundation | ||
| import struct SmithyCodegenCore.CodeGenerator | ||
| import struct SmithyCodegenCore.SwiftSettings |
There was a problem hiding this comment.
This file adds new params to support various new code generator features, plus the operations & type registry Swift files.
| /// along with other shape types, and all Shape IDs are fully-qualified | ||
| /// (i.e. members have the enclosing shape's namespace & name, along with their own member name.) | ||
| /// - Parameter astModel: The JSON AST model to create a `Model` from. | ||
| /// - Parameter astModel: The JSON AST model to load into the `Model` being created. |
There was a problem hiding this comment.
In this file, we add support for the rename field on Service, and the collectionOperationIDs and resourceIDs fields on Resource, which are needed to support all AWS services & protocol tests.
| @@ -34,98 +34,7 @@ extension Model { | |||
| return sinceDate > cutoff | |||
| } | |||
|
|
|||
There was a problem hiding this comment.
The code immediately below was moved to its own source file in Sources/SmithyCodegenCore/ModelTransformer/Model+TrimReferences.swift.
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| extension Model { |
There was a problem hiding this comment.
This model transformer removes unspecified operations from the service. If no operations are specified, all operations are preserved.
This is used to support internal service clients.
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| extension Model { |
There was a problem hiding this comment.
This was previously a helper function in the Model+Deprecated transform, but has been separated out into its own reusable transform.
It's used to "clean up" a model after it has had shapes removed, by also removing any references or shapes that depended on the removed shapes.
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
|
|
||
| struct OperationsCodegen { |
There was a problem hiding this comment.
Here, we code-generate a service's operations as a set of internal-scoped static variables namespaced under the client.
| // serialize the error member | ||
| if try shape.hasTrait(StreamingTrait.self) && member.target.hasTrait(ErrorTrait.self) { | ||
| continue | ||
| } |
There was a problem hiding this comment.
The above logic fixes an issue when serializing an event stream that contains error types.
| @@ -12,6 +12,8 @@ import struct Smithy.TraitCollection | |||
| /// A ``Shape`` subclass specialized for Smithy resources. | |||
| public class ResourceShape: Shape { | |||
| let operationIDs: [ShapeID] | |||
There was a problem hiding this comment.
Here & below, added support for the collectionOperations and resources fields, which are used by some AWS services.
| let operationIDs: [ShapeID] | ||
| let resourceIDs: [ShapeID] | ||
| let errorIDs: [ShapeID] | ||
| let renames: [ShapeID: String] |
There was a problem hiding this comment.
Added support here for service-closure renames, which are used by RestJson1 protocol tests.
| .replacingOccurrences(of: "Service", with: "") | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
The logic above was incorrect, and has been moved (with corrections) to SwiftSettings.
| switch shape.type { | ||
| case .structure, .union, .enum, .intEnum: | ||
| let base = shape.id.name | ||
| let baseName = (service.renames[shape.id] ?? shape.id.name).capitalized.escapingReservedWords |
There was a problem hiding this comment.
Here we check if a service-closure rename has been provided for this type, and if so, we use that as the base for the type name.
| throw SymbolProviderError("Shape has type .service but is not a ServiceShape") | ||
| } | ||
| return try "\(serviceShape.clientBaseName)Client" | ||
| return "\(settings.serviceName)Client" |
There was a problem hiding this comment.
Service name is now provided by SwiftSettings.
|
|
||
| import struct Smithy.ErrorTrait | ||
|
|
||
| struct TypeRegistryCodegen { |
There was a problem hiding this comment.
The (very simple!) code below generates a type registry containing all of this service's errors. Used for deserializing errored responses.
|
|
||
| // Perform model transformations here | ||
| let finalModel = try model | ||
| .withOperations(settings: settings) |
There was a problem hiding this comment.
Added this model transform to support internal clients.
|
|
||
| import struct Smithy.ShapeID | ||
|
|
||
| public struct SwiftSettings: Sendable { |
There was a problem hiding this comment.
This type captures the values encoded in the swift-settings.json file.
| import protocol Smithy.ResponseMessage | ||
| import struct Smithy.ShapeID | ||
|
|
||
| public protocol ClientProtocol<RequestType, ResponseType>: Sendable { |
There was a problem hiding this comment.
Each AWS protocol (and RPCv2CBOR) will provide an implementation of this protocol, which will be used by the Orchestrator to perform serde.
|
|
||
| import struct Smithy.Schema | ||
|
|
||
| public struct Operation<Input: SerializableStruct, Output: DeserializableStruct> { |
There was a problem hiding this comment.
The Operation structure contains references to input/output types, schemas, and the error type registry for a given operation.
An instance of this type is code-generated for every operation, and is used during request/response processing.
|
|
||
| import struct Smithy.Schema | ||
|
|
||
| public protocol OperationProperties: Sendable { |
There was a problem hiding this comment.
This protocol allows type-erased access to the schemas & type registry in an Operation.
| @@ -96,36 +97,36 @@ public extension ShapeSerializer { | |||
| func writeDocument(_ schema: Schema, _ value: any SmithyDocument) throws { | |||
| switch value.type { | |||
| case .blob: | |||
There was a problem hiding this comment.
Per the Smithy spec, documents & their components should be serialized & deserialized using prelude schemas.
The appropriate schemas are substituted below.
| import struct Smithy.Schema | ||
| import struct Smithy.ShapeID | ||
|
|
||
| public struct TypeRegistry: Sendable { |
There was a problem hiding this comment.
The TypeRegistry allows for a Shape ID or other schema property to be used to lookup the corresponding Swift type.
For now this is used for error deserialization, but will be used more broadly later for future Smithy features.
|
|
||
| import struct Foundation.Data | ||
|
|
||
| public protocol Codec: Sendable { |
There was a problem hiding this comment.
This protocol is used for obtaining the correct ShapeSerializer or ShapeDeserializer for a given protocol.
| deserializeFileURL: tempDirURL.appendingPathComponent("Deserialize.swift") | ||
| deserializeFileURL: tempDirURL.appendingPathComponent("Deserialize.swift"), | ||
| typeRegistryFileURL: tempDirURL.appendingPathComponent("TypeRegistry.swift"), | ||
| operationsFileURL: tempDirURL.appendingPathComponent("Operations.swift") |
There was a problem hiding this comment.
Update this test for new Swift generated files, and to use Swift settings.
Description of changes
Primary changes:
ClientProtocoltype, which will be used by theOrchestratorto serialize & deserialize requests & responses.Also:
smithy-model-info.jsontoswift-settings.json, which includes the same params as the Smithy-based code generator.Scope
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.